package com.cskaoyan.com.mylist;

import java.util.*;

public class MyArrayList <T> implements Iterable<T> {

    // 在有些JVM中, 对于数组需要预留与部分空间描述数组本身
    private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
    private static final int INIT_CAPACITY = 16; // 默认初始长度
    private Object[] objs; // MyArrayList底层真正用来存储数据的数组
    private int size; // MyArrayList数组中存储的元素个数
    private int modCount;

    // 构造方法
    public MyArrayList(){
        // this.objs = new Object[10];
        this.objs = new Object[INIT_CAPACITY];
    }
    public MyArrayList(int initCapacity){
        if (initCapacity < 1 || initCapacity > MAX_CAPACITY ){
            throw new IllegalArgumentException("initCapacity =" + initCapacity);
        }
        this.objs = new Object[initCapacity];
    }


    /**
     * 获取迭代器, 光标位于索引为 0 的元素的前面
     * @return 迭代器
     */
    @Override
    public ListIterator<T> iterator() {
        return new Itr(0);
    }

    /**
     * 获取迭代器, 光标位于索引为index元素的前面
     * @param index 索引
     * @return 迭代器
     */
    public ListIterator<T> iterator(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index=" + index + ", size=" + size);
        }
        return new Itr(index);
    }


    private class Itr implements ListIterator<T> {
        // 属性
        int cursor; //光标后面元素的索引
        int expModCount = modCount;
        int lastRet = -1; //-1表示最近没有返回元素,或者是最近返回的元素已经失效。

        // 构造方法
        Itr(int index) {
            cursor = index;
        }

        /**
         * 判断光标后面是否还有元素
         * @return 如果还有元素返回true, 否则返回false
         */
        @Override
        public boolean hasNext() {
            return cursor != size;
        }

        /**
         * 将光标往后移动一步, 并返回光标越过的元素
         * @return 光标越过的元素
         */
        @Override
        public T next() {
            // 判断迭代器是否有效
            checkConModException();
            // 判断光标后面是否还有元素
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            lastRet = cursor;
            cursor++;
            return (T) objs[lastRet];
        }


        /**
         * 检查在这次迭代过程中, 源MyArrayList的数据是否被别的数据修改了
         */
        private void checkConModException() {
            if (expModCount != modCount) {
                throw new ConcurrentModificationException();
            }
        }

        /**
         * 判断光标前面是否还有元素
         * @return 如果还有元素返回true, 否则返回false
         */
        @Override
        public boolean hasPrevious() {
            return cursor != 0;
        }

        /**
         * 将光标往前移动一步, 并返回光标越过的元素
         * @return 光标越过的元素
         */
        @Override
        public T previous() {
            // 检查并发修改异常
            checkConModException();
            // 判断光标前面是否还有元素
            if (!hasPrevious()) {
                throw new NoSuchElementException();
            }
            // 移动光标
            lastRet = --cursor;
            return (T) objs[lastRet];
        }

        /**
         * 获取光标后面元素的索引
         * @return 光标后面元素的索引
         */
        public int nextIndex() {
            return cursor;
        }

        /**
         * 获取光标前面元素的索引
         * @return 光标前面元素的索引
         */
        public int previousIndex() {
            return cursor - 1;
        }

        /**
         * 在光标后面添加元素
         * @param e 待添加的元素
         */
        public void add(T e) {
            checkConModException();
            MyArrayList.this.add(cursor, e);
            // 修改迭代器的属性
            expModCount = modCount;
            cursor++;
            lastRet = -1;
        }

        /**
         * 删除最近返回的元素
         */
        public void remove() {
            checkConModException();
            if (lastRet == -1) {
                throw new IllegalStateException();
            }
            MyArrayList.this.remove(lastRet);
            // 修改迭代器的属性
            expModCount = modCount;
            cursor = lastRet;
            lastRet = -1;
        }



        /**
         * 替换最近返回的元素
         * @param e 新值
         */
        public void set(T e) {
            checkConModException();
            if (lastRet == -1) {
                throw new IllegalStateException();
            }
            // 替换元素
            objs[lastRet] = e;
        }
    }


    /**
     * MyArrayList根据内容的添加方法
     * @param value: 要添加的内容
     * @return: 添加是否成功
     */
    public boolean add(T value){
        // 数组是否满了
        if (size == objs.length){
            // 数组满了, 先扩容
            int newLen = getLen(); // 获取一个新的长度以供扩容
            grow(newLen);// 根据指定长度扩容
        }

        modCount++;
        // 添加位置: 数组尾部,
        objs[size] = value;
        size++;

        return true;
    }
    // 获得一个新的扩容的长度
    private int getLen() {
        int oldLen = objs.length;
        int newLen = oldLen << 1; // oldLen* 2

        if (newLen < 0 || newLen > MAX_CAPACITY){
            newLen = MAX_CAPACITY;
        }
        // 逻辑上: oldLen旧数组长度已经是最大值
        if (oldLen == newLen){
            // 存不了
            throw new RuntimeException("list is full");
        }
        return newLen;
    }
    // 根据新长度扩容
    private void grow(int newLen) {
        // 根据新长度, 创建一个新的数组
        Object[] newObjs = new Object[newLen];
        // 把旧数组数组, 转移到新数组
        for (int i = 0; i < objs.length; i++) {
            newObjs[i] = objs[i];
        }
        this.objs = newObjs;
    }

    /**
     * MyArrayList根据内容的删除方法
     * @param value: 要删除的内容
     * @return: 删除是否成功
     */
    public boolean remove(T value){
        // 判断一下容器是否为空
        if (isEmpty()){
            // 抛异常或者返回假
            return false;
        }

        // 先要找到要删除值的下标位置
        int tag = -1; // 用来标记要删除数据的位置

        for (int i = 0; i < size; i++) {
            // 用当前的数组的遍历位置存储的内容objs[i] 和 要找的value做比较
            if (Objects.equals(value, objs[i])){
                // 找到了 i位置存储的就是要删除的内容
                tag = i;
                break;
            }
        }

        // 移动数据: 前移一位, 从找到的tag这个位置

        // 有可能这个数组中没有存储这个要删除的内容
        if (tag == -1){
            return false;
        }
        // 找到了
        for (int i = tag; i < size-1; i++) {
            objs[i] = objs[i+1];
        }
        //
        // objs[size-1] = null;
        size--;
        modCount++;

        return true;
    }

    /**
     *  根据内容的查找方法
     * @param value: 要查找的内容
     * @return: 是否存在
     */
    public boolean contains(T value){
        // 判断一下容器是否为空
        if (isEmpty()){
            // 抛异常或者返回假
            return false;
        }

        for (int i = 0; i < size; i++) {
            // 用当前的数组的遍历位置存储的内容objs[i] 和 要找的value做比较
            if (Objects.equals(value, objs[i])){
                // 找到了 i位置存储的就是要删除的内容
                return true;
            }
        }
        return false;
    }

    /**
     * 根据内容的修改方法
     * @param oldValue: 要修改的旧值
     * @param newValue: 用来替换的新值
     * @return: 替换是否成功
     */
    public boolean set(T oldValue, T newValue){
        // 判断一下容器是否为空
        if (isEmpty()){
            // 抛异常或者返回假
            return false;
        }

        for (int i = 0; i < size; i++) {
            // 用当前的数组的遍历位置存储的内容objs[i] 和 要找的value做比较
            if (Objects.equals(oldValue, objs[i])){
                // 找到了 i位置存储的就是要删除的内容
                objs[i]  = newValue;
                modCount++;
                return true;
            }
        }
        return false;
    }


    /**
     * 根据下标的添加方法
     * @param index: 要添加的下标位置
     * @param value: 要添加的内容
     * @return: 添加是否成功
     */
    public boolean add(int index, T value){
        // 判断下标是否合法
        if (index < 0 || index > size){
            // 返回假 或者 抛出异常
            return false;
        }
        // 是否需要扩容
        if (size == objs.length){
            int newLen = getLen();
            grow(newLen);
        }

        // 把index位置,以及index之后的数据, 向后移动一位, 腾出添加位置
        for (int i = size-1; i >= index ; i--) {
            objs[i+1] = objs[i];
        }

        objs[index] = value;
        size++;
        modCount++;
        return true;
    }

    /**
     * 根据下标的删除方法
     * @param index: 要删除的下标位置
     * @return: 被删的内容
     */
    public T remove(int index){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("paramer is Illegal");
            // return null;
        }

        // 保存旧值
        T oldValue = (T)objs[index];

        for (int i = index; i < size-1 ; i++) {
            objs[i] = objs[i+1];
        }
        size--;
        modCount++;
        return oldValue;
    }

    /**
     * 根据下标的查找方法
     * @param index: 要查找的下标位置
     * @return: 这个下标位置存储的内容
     */
    public T get(int index){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("paramer is Illegal");
            // return null;
        }

        return (T)objs[index];
    }

    /**
     * 根据下标的修改方法
     * @param index: 要修改的下标位置
     * @param newValue: 用来替换的新值
     * @return: 被替换的旧值
     */
    public T set(int index, T newValue){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("paramer is Illegal");
            // return null;
        }

        T oldValue = (T) objs[index];

        objs[index] = newValue;
        modCount++;
        return oldValue;
    }

    public boolean isEmpty(){
        return size == 0;
    }
    // 数组:  初始化, 扩容(数组存满了, 添加时候存满)


    @Override
    public String toString() {

        StringBuffer buffer = new StringBuffer();

        for (int i = 0; i < size; i++) {
            buffer.append(objs[i] + "   ");
        }


        return buffer.toString();
    }
}
